package common.util;

import com.alibaba.druid.support.logging.Log;
import com.alibaba.druid.support.logging.LogFactory;
import com.alibaba.druid.util.StringUtils;
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.common.utils.BinaryUtil;
import com.aliyun.oss.model.*;
import common.model.ResponseModelBootstrapTable;
import net.sf.json.JSONObject;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.net.URL;
import java.util.*;

/**
 * 阿里云Oss调用工具
 *
 * @author mac
 */
public class AliyunOssUtil {
	Log log = LogFactory.getLog(AliyunOssUtil.class);

	// 阿里云外网域名
	// 阿里云外网域名
	public final static String oss_outnet_url = "http://oss-cn-beijing.aliyuncs.com";
	public final static String oss_head_url = "oss-cn-beijing.aliyuncs.com";
	// 阿里云内网域名
	public final static String oss_innet_url = "http://oss-cn-beijing.aliyuncs.com";
	public static String accessKeyId = "LTAI2bVSv5CgM4ZF";
	public static String accessKeySecret = "yDR5JH4KIKB2j967w1Rf9xx1HstsmI";
	// 空间
	private static String bucketName = "nmtc";
	// 文件存储目录
	private static String filedir = "images/";
	private static OSSClient ossClient;

	public AliyunOssUtil() {
		ossClient = new OSSClient(oss_outnet_url, accessKeyId, accessKeySecret);
	}

	public void destory() {
		ossClient.shutdown();
	}

	/**
	 * 上传到OSS服务器 如果同名文件会覆盖服务器上的
	 *
	 * @param instream 文件流
	 * @param fileName 文件名称 包括后缀名
	 * @return 出错返回"" ,唯一MD5数字签名
	 */
	public String uploadFile2OSS(InputStream instream, String fileName) {
		String ret = "";
		try {
			// 创建上传Object的Metadata
			ObjectMetadata objectMetadata = new ObjectMetadata();
			objectMetadata.setContentLength(instream.available());
			objectMetadata.setCacheControl("no-cache");
			objectMetadata.setHeader("Pragma", "no-cache");
			objectMetadata.setContentType(getcontentType(fileName
					.substring(fileName.lastIndexOf("."))));
			objectMetadata.setContentDisposition("inline;filename=" + fileName);
			// 上传文件
			PutObjectResult putResult = ossClient.putObject(bucketName, filedir
					+ fileName, instream, objectMetadata);
			ret = putResult.getETag();
		} catch (IOException e) {
			log.error(e.getMessage(), e);
		} finally {
			try {
				if (instream != null) {
					instream.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return ret;
	}

	/**
	 * 获得图片路径
	 *
	 * @param fileUrl
	 * @return
	 */
	public String getImgUrl(String fileUrl) {
		if (!StringUtils.isEmpty(fileUrl)) {
			String[] split = fileUrl.split("/");
			return this.getUrl(this.filedir + split[split.length - 1]);
		}
		return null;
	}

	/**
	 * 上传图片
	 *
	 * @param url
	 */
	public void uploadImg2Oss(String url) {
		File fileOnServer = new File(url);
		FileInputStream fin;

		try {
			fin = new FileInputStream(fileOnServer);
			String[] split = url.split("/");
			this.uploadFile2OSS(fin, split[split.length - 1]);
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}

	}

	/**
	 * 上传图片
	 *
	 * @param url
	 */
	public void uploadImg2Oss(String url, String fileName) {
		File fileOnServer = new File(url);
		FileInputStream fin;
		try {
			fin = new FileInputStream(fileOnServer);
			this.uploadFile2OSS(fin, fileName);
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}

	}


	public String uploadImg2Oss(MultipartFile file) {

		String originalFilename = file.getOriginalFilename();
		String substring = originalFilename.substring(
				originalFilename.lastIndexOf(".")).toLowerCase();
		Random random = new Random();
		String name = random.nextInt(10000) + System.currentTimeMillis()
				+ substring;
		try {
			InputStream inputStream = file.getInputStream();
			this.uploadFile2OSS(inputStream, name);
			return name;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return name;
	}

	/**
	 * 获得url链接
	 *
	 * @param key
	 * @return
	 */
	public String getUrl(String key) {
		// 设置URL过期时间为10年 3600l* 1000*24*365*10
		Date expiration = new Date(new Date().getTime() + 3600l * 1000 * 24
				* 365 * 10);
		// 生成URL
		URL url = ossClient.generatePresignedUrl(bucketName, key, expiration);
		if (url != null) {
			return url.toString();
		}
		return null;
	}

	public String getRealUrl(String key) {
		// 设置URL过期时间为10年 3600l* 1000*24*365*10
		String re = "http://"+bucketName+"."+oss_head_url+key;
		return re;
	}

	/**
	 * Description: 判断OSS服务文件上传时文件的contentType
	 *
	 * @param FilenameExtension 文件后缀
	 * @return String
	 */
	public static String getcontentType(String FilenameExtension) {
		if (FilenameExtension.equalsIgnoreCase("bmp")) {
			return "image/bmp";
		}
		if (FilenameExtension.equalsIgnoreCase("gif")) {
			return "image/gif";
		}
		if (FilenameExtension.equalsIgnoreCase("jpeg")
				|| FilenameExtension.equalsIgnoreCase("jpg")
				|| FilenameExtension.equalsIgnoreCase("png")) {
			return "image/jpeg";
		}
		if (FilenameExtension.equalsIgnoreCase("html")) {
			return "text/html";
		}
		if (FilenameExtension.equalsIgnoreCase("txt")) {
			return "text/plain";
		}
		if (FilenameExtension.equalsIgnoreCase("vsd")) {
			return "application/vnd.visio";
		}
		if (FilenameExtension.equalsIgnoreCase("pptx")
				|| FilenameExtension.equalsIgnoreCase("ppt")) {
			return "application/vnd.ms-powerpoint";
		}
		if (FilenameExtension.equalsIgnoreCase("docx")
				|| FilenameExtension.equalsIgnoreCase("doc")) {
			return "application/msword";
		}
		if (FilenameExtension.equalsIgnoreCase("xml")) {
			return "text/xml";
		}
		return "image/jpeg";
	}

	public static void main(String[] args) {
		AliyunOssUtil ossUtil = new AliyunOssUtil();
		ossUtil.uploadImg2Oss("/Users/mac/Downloads/c25edaba6c0b14efa12524f6cc5fc53c.jpg");
		String imgUrl = ossUtil.getImgUrl("c25edaba6c0b14efa12524f6cc5fc53c.jpg");
		System.out.println(imgUrl);
	}

	/**
	 * 头像上串那个
	 *
	 * @return
	 */
	public static JSONObject getOSSToken() {
		String endpoint = oss_head_url;
		String accessId = accessKeyId;
		String accessKey = accessKeySecret;
		String bucket = bucketName;
		String dir = filedir;
		String host = "http://" + bucket + "." + endpoint;
		OSSClient client = new OSSClient(endpoint, accessId, accessKey);
		;
		try {
			long expireTime = 30;
			long expireEndTime = System.currentTimeMillis() + expireTime * 1000;
			Date expiration = new Date(expireEndTime);
			PolicyConditions policyConds = new PolicyConditions();
			policyConds.addConditionItem(PolicyConditions.COND_CONTENT_LENGTH_RANGE, 0, 1048576000);
			policyConds.addConditionItem(MatchMode.StartWith, PolicyConditions.COND_KEY, dir);

			String postPolicy = client.generatePostPolicy(expiration, policyConds);
			byte[] binaryData = postPolicy.getBytes("utf-8");
			String encodedPolicy = BinaryUtil.toBase64String(binaryData);
			String postSignature = client.calculatePostSignature(postPolicy);

			Map<String, String> respMap = new LinkedHashMap<String, String>();
			respMap.put("accessid", accessId);
			respMap.put("policy", encodedPolicy);
			respMap.put("signature", postSignature);
			//respMap.put("expire", formatISO8601Date(expiration));
			respMap.put("dir", dir);
			respMap.put("host", host);
			respMap.put("expire", String.valueOf(expireEndTime / 1000));
			JSONObject ja1 = JSONObject.fromObject(respMap);
			return ja1;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * /**
	 *
	 * @param key      指明文件名+扩展名
	 * @param partFile 要上传的文件
	 * @return 上传后的文件名
	 * @throws IOException
	 */
	public String multipartUpload(String key, File partFile, String bucketName) throws IOException {
		// TODO: 2018/1/17
		// 开始Multipart Upload
		InitiateMultipartUploadRequest initiateMultipartUploadRequest = new InitiateMultipartUploadRequest(bucketName, key);
		InitiateMultipartUploadResult initiateMultipartUploadResult = ossClient.initiateMultipartUpload(initiateMultipartUploadRequest);
		final int partSize = 1024 * 1024 * 5;
		// 计算分块数目
		int partCount = (int) (partFile.length() / partSize);
		if (partFile.length() % partSize != 0) {
			partCount++;
		}
		// 新建一个List保存每个分块上传后的ETag和PartNumber
		List<PartETag> partETags = new ArrayList<PartETag>();
		for (int i = 0; i < partCount; i++) {
			// 获取文件流
			FileInputStream fis = new FileInputStream(partFile);
			// 跳到每个分块的开头
			long skipBytes = partSize * i;
			fis.skip(skipBytes);
			// 计算每个分块的大小
			long size = partSize < partFile.length() - skipBytes ?
					partSize : partFile.length() - skipBytes;
			// 创建UploadPartRequest，上传分块
			UploadPartRequest uploadPartRequest = new UploadPartRequest();
			uploadPartRequest.setBucketName(bucketName);
			uploadPartRequest.setKey(key);
			uploadPartRequest.setUploadId(initiateMultipartUploadResult.getUploadId());
			uploadPartRequest.setInputStream(fis);
			uploadPartRequest.setPartSize(size);
			uploadPartRequest.setPartNumber(i + 1);
			UploadPartResult uploadPartResult = ossClient.uploadPart(uploadPartRequest);
			// 将返回的PartETag保存到List中。
			partETags.add(uploadPartResult.getPartETag());
			// 关闭文件
			fis.close();
		}
		CompleteMultipartUploadRequest completeMultipartUploadRequest =
				new CompleteMultipartUploadRequest(bucketName, key, initiateMultipartUploadResult.getUploadId(), partETags);
		// 完成分块上传
		CompleteMultipartUploadResult completeMultipartUploadResult =
				ossClient.completeMultipartUpload(completeMultipartUploadRequest);
		// 获得location

		return completeMultipartUploadResult.getKey();
	}


	/**
	 * easyPut
	 *
	 * @param key
	 * @param file
	 * @throws FileNotFoundException
	 */
	public void putEasy(String key, File file) throws FileNotFoundException {

		InputStream content = new FileInputStream(file);

		ObjectMetadata metadata = new ObjectMetadata();
		metadata.setContentLength(file.length());

		PutObjectResult result = ossClient.putObject(bucketName, key, content, metadata);

		System.out.println(result.getETag());
	}


	/**
	 * 判断是否上传成功
	 *
	 * @param key
	 * @return
	 */
	public boolean isUploadSuccess(String key) {
		ObjectMetadata objectMetadata = null;
		try {
			objectMetadata = ossClient.getObjectMetadata(bucketName, key);
		} catch (OSSException e) {
			//no suchKey
		}
		return objectMetadata != null;
	}

	/**
	 * 读取所有文件
	 *
	 * @return
	 */
	public ObjectListing getAllObject(String prefix) {
		return ossClient.listObjects(bucketName, prefix);
	}

	/**
	 * 分页获取object
	 */
	public ResponseModelBootstrapTable getAllObjectByPageSize(int limit, String nextKey, String keyPrefix) {
		ResponseModelBootstrapTable modelBootstrapTable = new ResponseModelBootstrapTable();
		//起始的object的key
		String nextMarker;
		if (nextKey != null && !"".equals(nextKey)) {
			nextMarker = nextKey;
		} else {
			nextMarker = null;
		}
		ObjectListing objectListing;
		// do {
		ListObjectsRequest listObjectsRequest = new ListObjectsRequest(bucketName);
		listObjectsRequest.setDelimiter("/");
		listObjectsRequest.setPrefix(keyPrefix);
		if (limit != 0) {
			objectListing = ossClient.listObjects(listObjectsRequest.withMarker(nextMarker).withMaxKeys(limit));
		} else {
			objectListing = ossClient.listObjects(listObjectsRequest.withMarker(nextMarker));
		}
		// objectListing = ossClient.listObjects(listObjectsRequest.withMarker(nextMarker));
		List<OSSObjectSummary> sums = objectListing.getObjectSummaries();
		List<String> commsums = objectListing.getCommonPrefixes();

		// for (OSSObjectSummary s : sums) {
		// 	System.out.println("\t" + s.getKey());
		// }
		modelBootstrapTable.setRows(sums);
		modelBootstrapTable.setObject(commsums);
		modelBootstrapTable.put("isHave", "" + objectListing.isTruncated());
		modelBootstrapTable.put("nextKey", "" + objectListing.getNextMarker());
		nextMarker = objectListing.getNextMarker();
		// } while (objectListing.isTruncated());
		return modelBootstrapTable;
	}

	/**
	 * 删除文件
	 *
	 * @param key
	 * @throws OSSException
	 */
	public void deleteObject(String key) throws OSSException {
		// 删除Object
		ossClient.deleteObject(bucketName, key);
	}

	/**
	 * url
	 *
	 * @param key
	 * @return
	 */
	public URL getObjectUrl(String key) {
		return ossClient.generatePresignedUrl(bucketName, key, new Date());
	}


	/**
	 * @param bucketName
	 * @return 创建Bucket
	 */
	@Deprecated
	public Bucket makeBucket(String bucketName) {
		boolean exist = ossClient.doesBucketExist(bucketName);
		if (exist) {
			System.out.println("The bucket exist.");
			try {
				throw new Exception("exist");
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return ossClient.createBucket(bucketName);
	}


	/**
	 * 上传一个文件，InputStream
	 *
	 * @param is
	 * @param key
	 */
	public static void uploadFile(InputStream is, String key) {
		PutObjectRequest putObjectRequest = new PutObjectRequest(
				bucketName, key, is);
		ossClient.putObject(putObjectRequest);
	}


	/**
	 * 上传一个文件，File
	 *
	 * @param file
	 * @param key
	 */
	public void uploadFile(File file, String key) {
		PutObjectRequest putObjectRequest = new PutObjectRequest(
				bucketName, key, file);
		ossClient.putObject(putObjectRequest);
		ossClient.shutdown();
	}


	/**
	 * @param key
	 * @return 下载一个文件到本地
	 */
	public OSSObject downloadFile(String key) {
		GetObjectRequest getObjectRequest = new GetObjectRequest(
				bucketName, key);
		return ossClient.getObject(getObjectRequest);
	}


	/**
	 * 上传某个文件到某个目录，key是自动生成的
	 *
	 * @param file
	 * @param dir
	 * @return
	 * @throws IOException
	 */
	public String uploadFile(MultipartFile file, String dir)
			throws IOException {
		if (null != file && !file.isEmpty() && file.getSize() > 0) {
			String fileName = UUID.randomUUID()
					+ "_"
					+ file.getOriginalFilename();
			String ymd = DateUtil.nowDate();
			String key = dir + ymd + "/" + fileName;
			AliyunOssUtil.uploadFile(file.getInputStream(), key);
			return key;
		}
		return null;
	}


	/**
	 * 创建目录，不能以斜杠“/”开头
	 *
	 * @param keySuffixWithSlash
	 */
	public void makeDir(String keySuffixWithSlash) {
		if (StringUtils.isEmpty(keySuffixWithSlash)) {
			return;
		}
		if (!keySuffixWithSlash.endsWith("/")) {
			keySuffixWithSlash += "/";
		}
		ossClient.putObject(bucketName, keySuffixWithSlash, new ByteArrayInputStream(new byte[0]));
	}


	/**
	 * 断点续传上传
	 *
	 * @param key
	 * @param filedir
	 * @throws Throwable
	 */
	public void uploadFileAsMultipart(String key, String filedir) throws Throwable {
		// 设置断点续传请求
		UploadFileRequest uploadFileRequest = new UploadFileRequest(bucketName, key);
		// 指定上传的本地文件
		uploadFileRequest.setUploadFile(filedir);
		// 指定上传并发线程数
		uploadFileRequest.setTaskNum(5);
		// 指定上传的分片大小
		uploadFileRequest.setPartSize(1024 * 1024);
		// 开启断点续传
		uploadFileRequest.setEnableCheckpoint(true);
		// uploadFileRequest.setObjectMetadata();

		ossClient.uploadFile(uploadFileRequest);
		ossClient.shutdown();
	}

}
